﻿///////////////////////////////////////////////////////////////////////////////
// Copyright 2016 lingzimaike@gmail.com
// GPLv2
// Author: lingzimaike
///////////////////////////////////////////////////////////////////////////////

#include "papa/thread/thread.h"
#include <cassert>

namespace papa {
namespace thread {

#if defined(__WINDOWS__)
	Thread::Thread(ThreadRunnable* runnable)
		: tid_(0)
		, state_(NOT_READY)
		, thread_handle_(-1L)
		, runnable_(runnable)
	{

	}

    Thread::Thread(::boost::scoped_ptr<ThreadRunnable>& runnable)
		: tid_(0)
		, state_(NOT_READY)
		, thread_handle_(-1L)
        , runnable_(NULL)
	{
        runnable_.swap(runnable);
	}

	Thread::~Thread(void)
	{
		if (thread_handle_ != -1L) {
			::CloseHandle((HANDLE)thread_handle_);
		}
	}

	bool Thread::Start(void)
	{
		assert(state_ == NOT_READY);
		state_ = READY;
		thread_handle_ = ::_beginthreadex(NULL, 0, 
			&Thread::thread_procedure, this, 0, (unsigned int*)&tid_);
		if (thread_handle_ != -1L) {
			return true;
		}
		state_ = NOT_READY;
		return false;
	}

	void Thread::Join(void)
	{
		assert(thread_handle_ != -1L);
		::WaitForSingleObject((HANDLE)thread_handle_, INFINITE);
		::CloseHandle((HANDLE)thread_handle_);
		thread_handle_ = -1L;
	}

	void Thread::Sleep(::time_t millisecond)
	{
		::Sleep((DWORD)millisecond);
	}

	Thread::TID_t Thread::get_current_tid(void)
	{
		return ::GetCurrentThreadId();
	}

	unsigned __stdcall Thread::thread_procedure(void* argument)
	{
		Thread* thread_ptr = static_cast<Thread*>(argument);
		assert(thread_ptr);
		thread_ptr->state_ = RUNNING;
		thread_ptr->runnable_->Run();
		thread_ptr->state_ = EXIT;
		return 0;
	}
#else
#endif // __WINDOWS__

}}  // namespace papa::thread